/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Global Trust Authority is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

use endorserment::entities::{cert_info, cert_revoked_list, cert_response::QueryResponse};
use endorserment::utils::utils::{
    generate_cert_id, get_cert_serial_number, get_cert_issuer_name, get_cert_subject_name
};
use openssl::asn1::Asn1Integer;
use openssl::bn::BigNum;
use openssl::nid::Nid;
use openssl::x509::{X509, X509Builder, X509NameBuilder};
use serde_json::json;
use std::collections::BTreeMap;

#[test]
fn test_get_cert_subject_name_when_result_not_empty_then_success() {
    // Create a certificate subject with common fields
    let mut name_builder = X509NameBuilder::new().unwrap();
    name_builder.append_entry_by_nid(Nid::COMMONNAME, "example.com").unwrap();
    name_builder.append_entry_by_nid(Nid::ORGANIZATIONNAME, "Example Org").unwrap();
    name_builder.append_entry_by_nid(Nid::COUNTRYNAME, "CN").unwrap();
    let subject_name = name_builder.build();

    let mut cert = X509::builder().unwrap();
    cert.set_subject_name(&subject_name).unwrap();
    let cert = cert.build();

    let result = get_cert_subject_name(&cert);

    // Parse the returned JSON string
    let parsed: BTreeMap<String, String> = serde_json::from_str(&result).unwrap();

    assert_eq!(parsed.get("commonName").unwrap(), "example.com");
    assert_eq!(parsed.get("organizationName").unwrap(), "Example Org");
    assert_eq!(parsed.get("countryName").unwrap(), "CN");
}

#[test]
fn test_get_cert_subject_name_when_result_empty_then_success() {
    // Create an empty certificate subject
    let name_builder = X509NameBuilder::new().unwrap();
    let subject_name = name_builder.build();

    let mut cert = X509::builder().unwrap();
    cert.set_subject_name(&subject_name).unwrap();
    let cert = cert.build();

    let result = get_cert_subject_name(&cert);

    // Empty subject should return an empty JSON object
    assert_eq!(result, "{}");
}

#[test]
fn test_get_cert_subject_name_when_special_chars_then_success() {
    let mut name_builder = X509NameBuilder::new().unwrap();
    name_builder.append_entry_by_nid(Nid::COMMONNAME, "321@example.com").unwrap();
    name_builder.append_entry_by_nid(Nid::ORGANIZATIONNAME, "Test & Demo, Inc.").unwrap();
    let subject_name = name_builder.build();

    let mut cert = X509::builder().unwrap();
    cert.set_subject_name(&subject_name).unwrap();
    let cert = cert.build();

    let result = get_cert_subject_name(&cert);

    let parsed: BTreeMap<String, String> = serde_json::from_str(&result).unwrap();

    assert_eq!(parsed.get("commonName").unwrap(), "321@example.com");
    assert_eq!(parsed.get("organizationName").unwrap(), "Test & Demo, Inc.");
}

#[test]
fn test_generate_cert_id_success() {
    // Test basic functionality
    let id1 = generate_cert_id("123", "test-issuer", "user1");
    assert!(!id1.is_empty());
    assert!(!id1.contains("-"));
    assert_eq!(id1.len(), 32);

    // Test that the same input produces the same output
    let id2 = generate_cert_id("123", "test-issuer", "user1");
    assert_eq!(id1, id2);

    // Test that different inputs produce different outputs
    let id3 = generate_cert_id("456", "test-issuer", "user1");
    assert_ne!(id1, id3);

    // Test empty string input
    let id4 = generate_cert_id("", "", "");
    assert!(!id4.is_empty());
    assert_eq!(id4.len(), 32);

    // Test special characters
    let id5 = generate_cert_id("123!@#", "test-issuer$%^", "user1&*()");
    assert!(!id5.is_empty());
    assert_eq!(id5.len(), 32);

    // Test long string
    let long_str = "a".repeat(1000);
    let id6 = generate_cert_id(&long_str, "test-issuer", "user1");
    assert!(!id6.is_empty());
    assert_eq!(id6.len(), 32);
}

#[test]
fn test_generate_cert_id_deterministic_success() {
    // Test determinism: multiple calls should produce the same result
    let inputs = vec![("123", "issuer1", "user1"), ("456", "issuer2", "user2"), ("789", "issuer3", "user3")];

    for (serial, issuer, user) in inputs {
        let id1 = generate_cert_id(serial, issuer, user);
        let id2 = generate_cert_id(serial, issuer, user);
        assert_eq!(id1, id2, "Generated IDs should be deterministic");
    }
}

#[test]
fn test_generate_cert_id_uniqueness_success() {
    // Test uniqueness: different inputs should produce different outputs
    let id1 = generate_cert_id("123", "issuer1", "user1");
    let id2 = generate_cert_id("123", "issuer1", "user2");
    let id3 = generate_cert_id("123", "issuer2", "user1");
    let id4 = generate_cert_id("456", "issuer1", "user1");

    let ids = vec![id1, id2, id3, id4];
    let unique_ids: std::collections::HashSet<_> = ids.iter().collect();
    assert_eq!(ids.len(), unique_ids.len(), "All generated IDs should be unique");
}

#[test]
fn test_get_cert_serial_number_success() {
    // Create a test certificate
    let mut builder = X509Builder::new().unwrap();

    // Set a known serial number
    let serial = BigNum::from_dec_str("123456789").unwrap();
    let serial_asn1 = Asn1Integer::from_bn(&serial).unwrap();
    builder.set_serial_number(&serial_asn1).unwrap();

    let cert = builder.build();

    // Test getting the serial number
    let result = get_cert_serial_number(&cert);
    assert_eq!(result, "075bcd15"); // Hexadecimal representation of 123456789
}

#[test]
fn test_get_cert_serial_number_when_serial_large_then_success() {
    // Create a test certificate
    let mut builder = X509Builder::new().unwrap();

    // Set a large serial number
    let serial = BigNum::from_dec_str("340282366920938463463374607431768211456").unwrap(); // 2^128
    let serial_asn1 = Asn1Integer::from_bn(&serial).unwrap();
    builder.set_serial_number(&serial_asn1).unwrap();

    let cert = builder.build();

    // Test getting the serial number
    let result = get_cert_serial_number(&cert);
    assert_eq!(result, "0100000000000000000000000000000000");
}

#[test]
fn test_get_cert_serial_when_number_zero_then_success() {
    // Create a test certificate
    let mut builder = X509Builder::new().unwrap();

    // Set serial number to 0
    let serial = BigNum::from_dec_str("0").unwrap();
    let serial_asn1 = Asn1Integer::from_bn(&serial).unwrap();
    builder.set_serial_number(&serial_asn1).unwrap();

    let cert = builder.build();

    // Test getting the serial number
    let result = get_cert_serial_number(&cert);
    assert_eq!(result, "");
}

#[test]
fn test_get_cert_issuer_name_when_result_not_empty_then_success() {
    // Create a certificate issuer with standard fields
    let mut name_builder = X509NameBuilder::new().unwrap();
    name_builder.append_entry_by_nid(Nid::COMMONNAME, "Test CA").unwrap();
    name_builder.append_entry_by_nid(Nid::ORGANIZATIONNAME, "Test Org").unwrap();
    name_builder.append_entry_by_nid(Nid::COUNTRYNAME, "CN").unwrap();
    let name = name_builder.build();

    let mut cert = X509::builder().unwrap();
    cert.set_issuer_name(&name).unwrap();
    let cert = cert.build();

    let result = get_cert_issuer_name(&cert);

    // Verify the result is a valid JSON string
    let parsed: BTreeMap<String, String> = serde_json::from_str(&result).unwrap();
    assert_eq!(parsed.get("commonName").unwrap(), "Test CA");
    assert_eq!(parsed.get("organizationName").unwrap(), "Test Org");
    assert_eq!(parsed.get("countryName").unwrap(), "CN");
}

#[test]
fn test_get_cert_issuer_name_when_result_empty_then_success() {
    // Create an empty certificate issuer
    let name = X509NameBuilder::new().unwrap().build();

    let mut cert = X509::builder().unwrap();
    cert.set_issuer_name(&name).unwrap();
    let cert = cert.build();

    let result = get_cert_issuer_name(&cert);

    // Verify the result is an empty JSON object string
    assert_eq!(result, "{}");
}

#[test]
fn test_get_cert_issuer_name_when_special_chars_then_success() {
    let mut name_builder = X509NameBuilder::new().unwrap();
    name_builder.append_entry_by_nid(Nid::COMMONNAME, "Test CA Special Characters !@#$%^").unwrap();
    let name = name_builder.build();

    let mut cert = X509::builder().unwrap();
    cert.set_issuer_name(&name).unwrap();
    let cert = cert.build();

    let result = get_cert_issuer_name(&cert);

    // Verify that the result handles special characters correctly
    let parsed: BTreeMap<String, String> = serde_json::from_str(&result).unwrap();
    assert_eq!(parsed.get("commonName").unwrap(), "Test CA Special Characters !@#$%^");
}

#[test]
fn test_get_cert_issuer_name_when_multiple_values_then_success() {
    // Create a certificate issuer with multiple fields of the same type
    let mut name_builder = X509NameBuilder::new().unwrap();
    name_builder.append_entry_by_nid(Nid::ORGANIZATIONALUNITNAME, "Unit1").unwrap();
    name_builder.append_entry_by_nid(Nid::ORGANIZATIONALUNITNAME, "Unit2").unwrap();
    let name = name_builder.build();

    let mut cert = X509::builder().unwrap();
    cert.set_issuer_name(&name).unwrap();
    let cert = cert.build();

    let result = get_cert_issuer_name(&cert);

    // Verify the result correctly handles multiple values
    let parsed: BTreeMap<String, String> = serde_json::from_str(&result).unwrap();
    assert!(parsed.get("organizationalUnitName").unwrap().contains("Unit2"));
}

#[test]
fn test_convert_to_query_response_when_certs_empty_then_success() {
    let certs = Vec::new();
    let response = QueryResponse::from_models(certs);
    assert!(response.message.is_none());
    assert!(response.certs.is_empty());
}

#[test]
fn test_convert_to_query_response_when_without_revoked_then_success() {
    let cert = cert_info::Model {
        id: "test_id".to_string(),
        name: Some("test_name".to_string()),
        description: Some("test_description".to_string()),
        cert_info: Some(Vec::from("test_content")),
        cert_type: Some(json!(["test_type"])),
        is_default: Some(true),
        version: Some(1),
        create_time: Some(1234567890),
        update_time: Some(1234567890),
        valid_code: Some(1),
        ..Default::default()
    };

    let certs = vec![(cert, None)];
    let response = QueryResponse::from_models(certs);

    assert!(response.message.is_none());
    assert_eq!(response.certs.len(), 1);
    let cert_resp = &response.certs[0];
    assert_eq!(cert_resp.cert_id, Some("test_id".to_string()));
    assert_eq!(cert_resp.cert_name, Some("test_name".to_string()));
    assert_eq!(cert_resp.description, Some("test_description".to_string()));
    assert_eq!(cert_resp.content, Some("test_content".to_string()));
    assert_eq!(cert_resp.cert_type, Some(vec!["test_type".to_string()]));
    assert_eq!(cert_resp.is_default, Some(true));
    assert_eq!(cert_resp.version, Some(1));
    assert_eq!(cert_resp.create_time, Some(1234567890));
    assert_eq!(cert_resp.update_time, Some(1234567890));
    assert_eq!(cert_resp.valid_code, Some(1));
    assert!(cert_resp.cert_revoked_date.is_none());
    assert!(cert_resp.cert_revoked_reason.is_none());
}

#[test]
fn test_convert_to_query_response_when_with_revoked_then_success() {
    let cert = cert_info::Model {
        id: "test_id".to_string(),
        name: Some("test_name".to_string()),
        cert_type: Some(json!(["test_type"])),
        valid_code: Some(2), // revoked
        ..Default::default()
    };
    let revoked = cert_revoked_list::Model {
        id: "test_id".to_string(),
        cert_revoked_date: Some(1234567890),
        cert_revoked_reason: Some("test_reason".to_string()),
        ..Default::default()
    };

    let certs = vec![(cert, Some(revoked))];
    let response = QueryResponse::from_models(certs);

    assert!(response.message.is_none());
    assert_eq!(response.certs.len(), 1);
    let cert_resp = &response.certs[0];
    assert_eq!(cert_resp.cert_id, Some("test_id".to_string()));
    assert_eq!(cert_resp.cert_name, Some("test_name".to_string()));
    assert_eq!(cert_resp.cert_type, Some(vec!("test_type".to_string())));
    assert_eq!(cert_resp.valid_code, Some(2));
    assert_eq!(cert_resp.cert_revoked_date, Some(1234567890));
    assert_eq!(cert_resp.cert_revoked_reason, Some("test_reason".to_string()));
}

#[test]
fn test_convert_to_query_response_when_multiple_certs_then_success() {
    let cert1 =
        cert_info::Model { id: "test_id_1".to_string(), name: Some("test_name_1".to_string()), ..Default::default() };

    let cert2 =
        cert_info::Model { id: "test_id_2".to_string(), name: Some("test_name_2".to_string()), ..Default::default() };

    let revoked = cert_revoked_list::Model {
        id: "test_id_2".to_string(),
        cert_revoked_date: Some(1234567890),
        cert_revoked_reason: Some("test_reason".to_string()),
        ..Default::default()
    };

    let certs = vec![(cert1, None), (cert2, Some(revoked))];
    let response = QueryResponse::from_models(certs);

    assert!(response.message.is_none());
    assert_eq!(response.certs.len(), 2);

    // Verify the first certificate (not revoked)
    let cert_resp1 = &response.certs[0];
    assert_eq!(cert_resp1.cert_id, Some("test_id_1".to_string()));
    assert_eq!(cert_resp1.cert_name, Some("test_name_1".to_string()));
    assert!(cert_resp1.cert_revoked_date.is_none());
    assert!(cert_resp1.cert_revoked_reason.is_none());

    // Verify the second certificate (revoked)
    let cert_resp2 = &response.certs[1];
    assert_eq!(cert_resp2.cert_id, Some("test_id_2".to_string()));
    assert_eq!(cert_resp2.cert_name, Some("test_name_2".to_string()));
    assert_eq!(cert_resp2.cert_revoked_date, Some(1234567890));
    assert_eq!(cert_resp2.cert_revoked_reason, Some("test_reason".to_string()));
}